#include "frame_pool_factory.h"
#include <algorithm>
#include <sstream>

bool FramePoolFact::Init()
{
	// TODO: load parameters from configuration file
	return true;
}
bool FramePoolFact::Fini()
{
	for (const auto& pool : poolList)
	{
		bool status = pool.get()->Fini();
		if (!status)
		{
			return false;
		}
	}
	return true;
}
bool FramePoolFact::CreatePool(size_t spliceSize, size_t spliceCnt, size_t expandingCnt)
{
	auto it = std::find_if(poolList.begin(), poolList.end(),
		[spliceSize](const FramePoolPtr& pool)
		{
			return pool->GetSpliceSize() >= spliceSize;
		});
	if (it == poolList.end())
	{
		auto pool = std::make_shared<FramePool>(spliceSize, spliceCnt, expandingCnt);
		ASSERT(pool != nullptr);
		if (pool->Init())
		{
			poolList.emplace_back(std::move(pool));
			return true;
		}
		return false;
	}
	// reused already existing pool if spliceSize is the same
	if ((*it)->GetSpliceSize() == spliceSize)
	{
		return false;
	}
	auto pool = std::make_shared<FramePool>(spliceSize, spliceCnt, expandingCnt);
	ASSERT(pool != nullptr);
	if (pool->Init())
	{
		poolList.insert(it, pool);
		return true;
	}
	return false;
}
FramePtr FramePoolFact::BorrowFrame(size_t need)
{
	ASSERT(need > 0);
	for (const auto& pool : poolList)
	{
		ASSERT(pool != nullptr);
		if (pool->GetSpliceSize() > need)
		{
			return pool->BorrowFrame();
		}
	}
	// there is no proper pool to get frame
	return nullptr;
}
int FramePoolFact::BorrowFrames(std::vector<FramePtr>& frameVec, size_t need, size_t needCnt)
{
	ASSERT(need > 0);
	FramePoolPtr pool;
	auto it = std::find_if(poolList.begin(), poolList.end(),
		[need](const FramePoolPtr& pool)
		{
			return pool->GetSpliceSize() >= need;
		});
	if (it == poolList.end())
	{
		return -1;
	}
	pool = *it;
	ASSERT(pool != nullptr);
	return pool->BorrowFrames(frameVec, need, needCnt);
}
void FramePoolFact::ReturnFrames(std::vector<FramePtr>& frameVec)
{
	for (const auto& f : frameVec)
	{
		ASSERT(f != nullptr);
		f->ReturnFrame();
	}
	frameVec.clear();
}


std::string FramePoolFact::Audit()
{
	std::stringstream ss;
	for (const auto& pool : poolList)
	{
		ASSERT(pool != nullptr);
		ss << pool->Audit();
	}
	return ss.str();
}
